#! /usr/bin/python
#coding: utf-8
from MorphologicalRepresentation import *


class SemRepr:

    def __init__(self, matr):
        self._matr = matr.get_matr()
        self._arls = matr.get_arls().get_array()
        self._class1 = None
        self._class2 = None
        self._conj = [None for a in range(len(self._matr))]
        self._hasname = False
        self._i = None
        self._kindtext = matr.get_kindtext()
        self._mainpos = matr.get_mainpos()
        self._maxnumbsit = 0
        for a in self._matr:
            if a.mark and 'e' in a.mark:
                self._maxnumbsit += 1
        self._nmasters = matr.get_nmasters()
        self._numbqswds = matr.get_numbqswd()
        self._pos1 = None
        self._rc = matr.get_rc().get_array()
        self._sembase = [None for a in range(len(self._rc))]
        self._semdes = [None for a in range(len(self._rc))]
        self._semrepr = ''
        self._sems = ''
        self._timevarnumb = 0
        self._used = []
        self._sitdescr = [{'expr':None,'mark':None} for a in range(len(self._rc))]
        self._performers = [None for a in range(len(self._rc))]

        self._build()

    def _build_sem_des(self, i, c, sem):
        sembase = self._sembase
        semdes = self._semdes
        matr = self._matr
        performers = self._performers
        rc = self._rc

        if c == 1:
            """
                Отображение семантики прилагательных в массиве  sembase
            """
            if self._kindtext != 'specqs-properties':

                if not i or 3 not in rc[i - 1].tclass:
                    # если прилагательное первое в списке
                    sembase[i] = self._transform1(sem)
                else:
                    sembase[i] =  sembase[i]  + self._transform1(sem)

        elif c == 2:
            """
                Обработка конструкта
            """
            sembase[i] = sem
            performers[i] = rc[i].unit

        elif c == 3:
            """
                Обработка названий
            """
            name = rc[i + 1].unit
            if '*' not in performers[i]:
                performers[i] += u'* (Название,' + name + ')'
            else:
                performers[i] += u' (Название,' + name + ')'

        elif c == 4:
            """
                Обработка существительных собственных
            """
            sembase[i] = sem
            semdes[i] = sembase[i]
            performers[i] = semdes[i] + ' : ' + matr[i].mark

        elif c == 5:
            """
                Обработка нарицательных существительных
            """
            #если слева есть прилагательные, то они добавляются
            sembase[i] = sem + '*' + sembase[i - 1] if self._matr[i]['nattr'] else sem
            ref = u'нек'
            self._semdes[i] = ref  + ' ' + sembase[i]
            self._performers[i] = semdes[i]
            if self._hasname:
                #Обработка названий
                name = rc[i + 1].unit
                if '*' not in performers[i]:
                    performers[i] += u'* (Название,' + name + ')'
                else:
                    performers[i] += u' (Название,' + name + ')'
                self._hasname = 0
            self._performers[i] +=' : ' + self._matr[i].mark


        elif c == 6:
            """
                Обработка сочетаний с существительными, обозначающих множества объектов.
                Пример контекста  – “Поступили 5 трехтонных контейнеров.
            """
            n = self._matr[i].qt
            self._sembase[i] = sem
            if n:
                self._semdes[i] = u'нек множ * (Колич,' + n + u')(Кач-состав,' +  sembase[i] + ')'
            else:
                self._semdes[i] = u'нек множ * (Кач-состав,' +  sembase[i] + ')'
            #первый символ цепочки sem, если считать символами элементы
            #первичного информационного универсума X(B(Cb(Lingb))) и переменные
            beg = self._sems[0]
            var1 = self._matr[i].mark
            var2 = self._varbuild(i, matr, var1)
            #запоминаем порядковый номер в массиве
            if self._kindtext == 'specqs-properties':
                self._i = i
                self._semdes[i] = self._semdes[i][:-1] + '*' + self._fetch_rel_from_dependend_adj(i) + ')'
            self._performers[i] = u'произвольн ' + beg + u'* Элем(' + self._semdes[i] +' : ' + var1 + '): ' + var2


        elif c == 7:
            """
               Построение фрагмента семантического представления (СП) текста Т,
               являющегося сочетанием, включающим собирательное существительное
               (“индийская керамика”, “итальянская обувь” и т.п.)
            """
            if POS_TAGS.ADJECTIVE not in self._rc[i - 1].tclass:
                semdes[i] = sem
            else:
                prop = self._sembase[i - 1]
                self._semdes[i] = self._transform2(prop, sem)
        elif c == 8:
            pass



    def _build(self):

        self.prepare_for_build_sr()

        self.initialize_sem_repr()

        self.display_situations()

        self.finalize_semrepr()

        print self._semrepr

    def display_situations(self):
        """
            Обработка прямых смысловых связей между глагольной формой и
            существительным или конструктом.
        """
        performers = self._performers
        matr = self._matr
        used = self._used
        rc = self._rc
        used = [0 for i in range(len(self._rc))]
        conj = [0 for i in range(self._maxnumbsit)]

        for m in range(len(self._rc)):
            cl1 = rc[m].tclass
            if any(c in [POS_TAGS.NOUN, 11] for c in cl1):
                #если найдено количество единиц текста, управляющих m–й единицей текста
                for q in range(len(matr[m].posdir)):
                    if q is None:
                        continue
                    p = matr[m].posdir[q]
                    if p is None or POS_TAGS.VERB not in rc[p].tclass:
                        #если управляющий элемент у существительного - другое существительное
                        #то нет смысла ввязывать его в отношение с глаголом
                        continue
                    cl2 = rc[p].tclass
                    if any(x in [POS_TAGS.VERB, POS_TAGS.PRICHASTIE] for x in cl2):
                        var2 = matr[p].mark
                        numbsit = int(var2[1:])
                        role = matr[m].reldir[q]

                    first = True
                    if POS_TAGS.NOUN in cl1 and POS_TAGS.ADJECTIVE not in cl1:
                        if self._kindtext not in ['specqs-relat1','specqs-quant1']:
                            if not used[m]:
                                actant = performers[m]
                            else:
                                if POS_TAGS.NOUN in cl1:
                                    actant = self._varbuild(m, matr, '')
                                elif 11 in cl1:
                                    actant = rc[m].unit

                        else:
                            if used[m] == 1 or (used[m] == 0 and matr[m].mark == 'S1'):
                                actant = self._varbuild(m, matr, '')
                            else:
                                actant = performers[m]
                        if not actant:
                            continue
                        if self._kindtext == 'specqs-estimation' and first:
                            self._sitdescr[numbsit - 1]['expr'] = self._sitdescr[numbsit - 1]['expr'].replace('@',actant)
                        #elif self._kindtext == 'specqs-way' and first:
                            #self
                        else:
                            self._sitdescr[numbsit - 1]['expr'] += '(' + role + ',' + actant + ')'

                        first = False

        # второй перебор элементов МССП для отражения связей между существительными
        for k in range(len(rc)):
            cl1 = rc[k].tclass
            if POS_TAGS.ADJECTIVE not in cl1 and (POS_TAGS.NOUN in cl1 or 11 in cl1):
                posmaster = matr[k].posdir[0]
                if posmaster is None:
                    print "Bad text!"
                else:
                    cl2 = rc[posmaster].tclass
                    if POS_TAGS.NOUN in cl2:
                        rel1 = matr[k].reldir[0]
                        varmaster = matr[posmaster].mark
                        if 11 in cl1:
                            arg2 = self._sembase[k]
                        #if 1 in cl1:
                        vardep = matr[k].mark
                        if used[k] == 0:
                            arg2 = performers[k]
                        else:
                            arg2 = vardep
                        #переменная varmaster соответствует существительному,
                        #управляющему единицей текста в позиции k, причем
                        #для самого этого существительного управляющей единицей
                        #является глагольная форма – глагол или причастие.
                        letter = varmaster[0]
                        if letter == 'x':
                            descr1 = rel1 + u'(' + varmaster + u',' + arg2 + u')'
                        else:
                            semhead = self._sembase[posmaster][0]
                            descr1 = rel1 + u'(произв' + semhead + u'*(Элем,' + varmaster + '),' + arg2 + ')'
                        """
                            Затем с помощью конъюнкции ^ к  выражению Sitdescr [numbsit, expr] ,
                            характеризующему рассматриваемую ситуацию с номером. numbsit,
                            справа приписывается выражение descr1
                        """
                        possit = matr[posmaster].posdir[0]
                        varsit = matr[possit].mark
                        numbsit = int(varsit[1:])
                        self._sitdescr[numbsit - 1]['expr'] += '&' + descr1
                        if not conj[numbsit-1]:
                            # признак использования конъюнкции в строке    Sitdescr [numbsit, expr]
                            conj[numbsit-1] = 1

    def finalize_semrepr(self):
        """
        pos2 = self._pos1
        while self._one_elem_in_array(self._class2, self._class1):
            pos2 += 1
            self._class2 = self._rc[pos2].tclass
        """
        kindtext = self._kindtext
        situations = ''
        for k in range(self._maxnumbsit):
            # для корректности добавлена ещё одна скобка
            event = self._sitdescr[k]['expr'] + ')'
            if self._conj[k] == 1:
                event = '(' + event + ')'
            if k == 0:
                situations = event
            else:
                situations += '&' + event
        if self._maxnumbsit > 1:
            situations = '(' + situations + ')'

        if kindtext == 'stat':
            self._semrepr = situations
        elif kindtext == 'imp':
            self._semrepr += '&' + situations + ')'
        elif kindtext == 'genqs':
            # Вопрос(S1, (Кач-состав(S1, гриб) & Свойство(произв гриб*(Элем, S1), ядовитость)))
            self._semrepr += '&' + situations + ')))'
        elif kindtext in ['specqs-relat1','specqs-relat2']:
            if u'Вопрос(x1,' in self._semrepr:
                self._semrepr += situations + ')'
            else:
                posmainnoun = self._right(self._mainpos, POS_TAGS.NOUN)
                sem1 = self._sembase[posmainnoun]
                if '*' not in sem1:
                    semhead = sem1
                else:
                    loc1 - matr[posmainnoun].locunit
                    semhead = self._arls[loc1]['sem']
                self._semrepr += sem1 + u') & Описание( произв' + semhead + u'*(Элем, S1):y1,' + situations + '))'

        elif kindtext == 'specqs-rol':
            # Вопрос(х1, Контент(х2, х1,нек опер.сист*(Марка, Windows)(Модель, 7)))
            unknowns = 'x1'
            if self._numbqswds > 1:
                for k in range(self._numbqswds - 1):
                    vrb = k[1:]
                    unknowns += '&' + vrb
                unknowns = '(' + unknowns + ')'
            self._semrepr += unknowns + ',' + situations + ')'
        elif kindtext == 'specqs-quant1':
            posmainnoun = self._right(mainpos, POS_TAGS.NOUN)
            sem1 = sembase[posmainnoun]
            if '*' not in sem1:
                semhead = sem1
            else:
                loc1 = matr[posmainnoun].locunit
                semhead = self._arls[loc1]['sem']
            self._semrepr += sem1 + u') & Описание ( произв' + semhead + u'* ( Элем . S1 ) :y1' + situations  + ') )'
        elif kindtext == 'specqs-estimation':
            # Вопрос(х3, (х3 = Цена(произв окно1*(Материал, Пластик)(Производитель, Европласт))))
            self._semrepr += situations +  ')'
        elif kindtext == 'specqs-way':
            # (Вопрос(Р1, Ситуация(е1, получение1*(Объект, нек паспорт*(Вид-пасп, Заграничный))))^Способ(е1, Р1))
           self._semrepr += situations + '))'
        elif kindtext == 'specqs-properties':
            # Вопрос(S1, (Кач-состав(S1, гриб) & Свойство(произв гриб*(Элем, S1), ядовитость)))
            set = 'S'
            for i in range(len(self._performers)):
                if 'S' + str(i) in self._performers[self._i]:
                    set += str(i)
                    break
            self._semrepr += set + ', ' + self._semdes[self._i] + ':' + set + ')'
        elif kindtext == 'specqs-download':
            # Вопрос(х1, Контент(х2, х1,нек опер.сист*(Марка, Windows)(Модель, 7)))
            self._semrepr +=   ', ' + situations + u'(URL, x10))'
        elif kindtext == 'specqs-cause':
            self._semrepr += u'P1, Причина(е1, P1)) &' + situations

        #print self._semrepr

    def _fetch_rel_from_dependend_adj(self, i):
        for j in range(len(self._matr)):
            if i == self._matr[j].posdir[0] and POS_TAGS.ADJECTIVE in self._rc[j].tclass:
                return self._matr[j].reldir[0]
            j+=1


    def _get_case(self, i, cl):
        """
            Возвращает вид случая
        """
        numb = None
        matr = self._matr
        c = None
        if POS_TAGS.ADJECTIVE in cl:
            c = 1
        elif 11 in cl:
            c = 2
        elif POS_TAGS.NOUN in cl and POS_TAGS.ADJECTIVE not in cl:
            if len(self._rc) - 1 > i:
                if POS_TAGS.PROPER_NOUN in self._rc[i + 1].tclass:
                    self._hasname = 1

            #число, относящееся к существительному в позиции k1
            numb = matr[i].qt
            ref = u'нек'
            sem = self._arls[i].semsit
            beg = ''
            sems = []
            b = False
            delimit = True
            # разбивает семантическое представление на составные единицы
            for a in sem:
                if a not in ' ,.:;%$#@!&*(){}[]/?\|':
                    delimit = False
                    beg += a
                    b = True
                elif b:
                    if not delimit:
                        delimit = True
                        sems.append(beg)
                        beg = ''
            else:
                if beg:
                    sems.append(beg)

            beg = sems[0]
            self._sems = sems


            #признак обозначения индивида, а не множества индивидов
            setind = 0
            l = len(sems)
            if l >= 2 and sems[1] == u'множ':
                setind = 1
            if numb in [0, 1] and beg == ref and not setind:
                c = 4
            if not numb and beg != ref and sem[0].islower():
                #т.е. RC[i].unit    – обозначение индивида, а не множества
                for c in self._rc[i].mcoord:
                    if c.num == 1:
                        c = 5
                        break
                else:
                    c = 6

            if not numb and setind == 1:
                c = 7
            #elif not numb:
                #c = 8
        return c

    def _one_elem_in_array(self, farray, sarray):
        return any(fitem in sarray for fitem in farray)

    def initialize_sem_repr(self):
        """
            формирования массивов Sembase, Semdes, Performers и
            начальной конфигурации массива  Sitdescr.
        """
        rc = self._rc
        matr = self._matr

        for i in range(len(rc)):
            try:

                cl = rc[i].tclass
                if not self._one_elem_in_array(cl, [POS_TAGS.CONJUNCTION, POS_TAGS.PROPER_NOUN, POS_TAGS.DELIMETER]):
                    loc = matr[i].locunit
                    sem = self._arls[loc].semsit

                if self._one_elem_in_array(cl, [POS_TAGS.VERB, POS_TAGS.PRICHASTIE]):
                    self.process_situations(i)
                elif self._one_elem_in_array(cl, [POS_TAGS.NOUN, POS_TAGS.ADJECTIVE, POS_TAGS.CONJUNCTION]):
                    c = self._get_case(i, cl)
                    # если прилагательное
                    """if 3 in cl:
                        if '*' not in self._arls[matr[i].posdir[0]].semsit:
                            self._arls[matr[i].posdir[0]].semsit += '*'
                        self._arls[matr[i].posdir[0]].semsit += self._arls[i].semsit
                    """
                    self._build_sem_des(i, c, self._arls[i].semsit)
            except:
                continue

    def prepare_for_build_sr(self):
        kindtext = self._kindtext
        rc = self._rc
        numb = None
        if kindtext == 'specqs-relat1':
            self._semrepr = u'Вопрос (x1,'
            numb = 1
        elif kindtext == 'specqs-relat2':
            self._semrepr = u'Вопрос (S1, (Кач-cостав (S1, '
            numb = 2
        elif kindtext == 'specqs-properties':
            # Вопрос(S1, (Кач-состав(S1, гриб) & Свойство(произв гриб*(Элем, S1), ядовитость)))
            self._semrepr = u'Вопрос( '
        elif kindtext == 'specqs-rol':
            self._semrepr = u'Вопрос ( '
        elif kindtext == 'specqs-download':
            # Вопрос(х1, Контент(х2, х1,нек опер.сист*(Марка, Windows)(Модель, 7)))
            self._semrepr = u'Вопрос( x10'
        elif kindtext == 'specqs-way':
            # (Вопрос(Р1, Ситуация(е1, получение1*(Объект, нек паспорт*(Вид-пасп, Заграничный))))^Способ(е1, Р1))
            self._semrepr = u'Вопрос(P1, Способ(P1, '
        elif kindtext == 'genqs':
            self._semrepr = u'Вопрос( х1 = Ист-знач ('
        elif kindtext == 'specqs-quant1':
            self._semrepr = u'Вопрос(x1, ((x1≡ Колич('
        elif kindtext == 'specqs-quant2':
            self._semrepr = u'Вопрос(x1, ((x1≡ Колич( S1)) & Кач-cостав (S1, сит) & Описание(произв сит * (Элемент, S1) : e1,'
        elif kindtext == 'specqs-estimation':
            # Вопрос(х3, (х3 = Цена(произв окно1*(Материал, Пластик)(Производитель, Европласт))))
            self._semrepr = u'Вопрос(х1, (х1 = '
        elif kindtext == 'specqs-cause':
            # Вопрос(х3, (х3 = Цена(произв окно1*(Материал, Пластик)(Производитель, Европласт))))
            self._semrepr = u'Вопрос( '
        elif kindtext == 'imp':
            self._semrepr = u'(Команда(#Оператор#, #Исполнитель#, #сейчас#,   e1)'
        elif kindtext == 'stat':
            self._semrepr = ''

    def process_situations(self, i):
        #набор морфологических признаков, связанный с глагольной формой в позиции i
        pos = self._rc[i].mcoord
        self._timevarnumb += 1
        vtime = 't' + str(self._timevarnumb)
        try:
            tense = pos[0].tense
        except:
            tense = 2
        timesit = ''
        if tense == 1:
            timesit = u'(Время, нек мом * (Раньше, #сейчас#) : ' + vtime + ')'
        elif tense  == 2:
            timesit = u'(Время, #сейчас#) '
        elif tense  == 3:
            timesit = u'(Время, нек мом * (Позже, #сейчас#) : ' + vtime + ')'

        linesit = self._matr[i].locunit
        consit = self._arls[i].semsit
        var = self._matr[i].mark
        numsit = int(var[1:])

        if self._kindtext == 'imp' and numsit == 1:
            self._sitdescr[numsit - 1]['expr'] = u'Цель (' + var + ',' + consit + '*'
        elif self._kindtext == 'specqs-estimation' and numsit == 1:
            self._sitdescr[numsit - 1]['expr'] = consit + '(@)' + timesit
        #if self._kindtext == 'specqs-way' and numsit == 1:
        #    self._sitdescr[numsit - 1]['expr'] = consit + '(@)' + timesit
        else:

            self._sitdescr[numsit - 1] = {'expr': u'Ситуация (' + var + ',' + consit + '*' + timesit,'mrk': var}

    def _right(self, pos, cl):
        """
            Возвращает первую информационную единицу ниже позиции pos
            c классом cl.
        """
        rc = self._rc
        for i in range(pos, len(rc)):
            pos = pos + 1
            if cl in rc[pos].tclass:
                return pos

    def _transform1(self, s):
        """
            Аргументы: s – строка вида r(z, b), где r – обозначение бинарного отношения,
            b – второй атрибут отношения, или вида  (f(z) ≡ b) ,
            где f - имя одноместной функции, b – строка, обозначающая значение функции,
            z – буква ‘z', интерпретируемая как переменная.
            Значение: строка  t  вида  (r, b)  в первом случае и вида  (f, b) во втором случае.
        """
        s = s.lstrip().rstrip()
        x = s.find('(')
        if not x:
            return s
        if x:
            # binary relations
            r = s[:x]
            b = s[s.find(','):]
            return r + b
        else:
            # function
            f = s[:s[1:].find('(') + 1]
            b = s[s.find('=') + 1:]
            return f + ',' + b


    def _transform2(self, s, t):
        """

        """
        u = ''
        n = None
        n = t.find('*')
        if n:
            u = t[:n] + s + t[n:]
        elif 'множ' not in t:
            u = t + '*' + s
        else:
            m = t.find(')')
            u = t[:m] + s + t[m:]

        return u

    def _varbuild(self, m, matr, v):
        if matr[m].mark[0] == 'S':
            v = 'y' + matr[m].mark[1:]
        else:
            v = matr[m].mark
        return v

    def get_semrepr(self):
        return self._semrepr
